package cn.wzl.perceptron.gif;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;

public class XyCoordinateSystem {

    protected BufferedImage bi;
    private final int width, height;
    private final int zeroPointX, zeroPointY;

    public XyCoordinateSystem(int maxX, int maxY) {
        this.zeroPointX = maxX;
        this.zeroPointY = maxY;
        this.width = zeroPointX * 2 + 1;
        this.height = zeroPointY * 2 + 1;
        bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = (Graphics2D) bi.getGraphics();
        drawBackGround(g2);
    }

    public void writeToFile(String fileName) throws IOException {
        ImageIO.write(bi,"JPEG",new FileOutputStream(fileName));
    }

    public Graphics2D retrievePen(Color color) {
        Graphics2D g2 = (Graphics2D) bi.getGraphics();
        g2.setColor(color);
        return g2;
    }

    private void drawBackGround(Graphics2D g2){
        g2.setColor(Color.WHITE);
        g2.fillRect(0,0,width,height);
        g2.setColor(Color.BLACK);
        drawLineWithWAndB(g2, 0,1,0);
        drawLineWithWAndB(g2, 1,0,0);
    }

    public void drawString(Graphics2D g2, String str, double x, double y) {
        drawStringInXyCoordinateSystem(g2, str, x, y);
    }

    private void drawStringInXyCoordinateSystem(Graphics2D g2,String str, double x, double y) {
        g2.drawString(str, (int) (x + zeroPointX),  (int)(-y + zeroPointY));
    }

    public void drawPoint(Graphics2D g2, double x, double y, double width) {
        drawPointInXyCoordinateSystem(g2, x, y, width);
    }

    private void drawPointInXyCoordinateSystem(Graphics2D g2, double x, double y, double width) {
        g2.fill(new Ellipse2D.Double(x + zeroPointX - width/2,  - y + zeroPointY - width/2, width, width));
    }

    //w1*x + w2*y + b = 0;
    public void drawLineWithWAndB(Graphics2D g2, double w1, double w2, double b) {
        if(w1 == 0 && w2 != 0) {
            this.drawLineWithWandBInXyCoordinateSystem(g2, -zeroPointX, (int)(-b/w2), zeroPointX, (int)(b/w2));
            return;
        }
        if(w1 != 0 && w2 == 0) {
            this.drawLineWithWandBInXyCoordinateSystem(g2, (-b/w1), -zeroPointY, (-b/w1), zeroPointY);
        }
        double y1 = retrieveYWithLineAndX(w1, w2, b, -zeroPointX);
        double y2 = retrieveYWithLineAndX(w1, w2, b, zeroPointX);
        double x1 = retrieveXWithLineAndY(w1, w2, b, -zeroPointY);
        double x2 = retrieveXWithLineAndY(w1, w2, b, zeroPointY);
        if(y1 > -zeroPointY && y1 < zeroPointY) {
            this.drawLineWithWandBInXyCoordinateSystem(g2, -zeroPointX, y1, zeroPointX, y2);
        }
        else{
            this.drawLineWithWandBInXyCoordinateSystem(g2, x1, -zeroPointY, x2, zeroPointY);
        }
    }

    private void drawLineWithWandBInXyCoordinateSystem(Graphics2D g2, double x1, double y1, double x2, double y2) {
        g2.drawLine((int) (x1 + zeroPointX), (int) - y1 + zeroPointY, (int)x2 + zeroPointX, (int) - y2 + zeroPointY);
    }

    private double retrieveYWithLineAndX(double w1, double w2, double b, double x) {
        return - (w1 * x + b) / w2;
    }

    private double retrieveXWithLineAndY(double w1, double w2, double b, double y) {
        return - (w2 * y + b) / w1;
    }



}
